/* 
 * Copyright (c) 2004-2005 Massachusetts Institute of Technology. This code was
 * developed as part of the Haystack (http://haystack.lcs.mit.edu/) research 
 * project at MIT. Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation files (the 
 * "Software"), to deal in the Software without restriction, including without 
 * limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom
 * the Software is furnished to do so, subject to the following conditions: 
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 */
/*
 * Created on Aug 21, 2004
 *
 */
package edu.mit.csail.relo.console;

import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/*
 * We provide support for default 
 * @author vineet
 *
 */
public class HelpSupport {
	public static HelpInfo helpInfo = new HelpInfo();

	private PrintStream out;
    
    public HelpSupport(PrintStream outStream) {
        out = outStream;
    }
    
    // utility methods
    private String getShortType(Class type) {
    	String t = type.toString();
    	int ndx = t.lastIndexOf(".");
    	return t.substring(ndx+1);
    }

    // support for publically scriptable methods (methods we expect the user to need)
    /*
     * Implementation Strategy:
     * Create a class, which all classes having scriptable methods have as a 
     * static instance. Just before all methods we will only need to just add 
     * documentation
     * 
     */
	static {
	    helpInfo.addMethodDesc("methods(obj)", "Returns methods and help description");
	}
    public void methods( Object obj) {
        HelpInfo hi = null;
        try {
            Field helpField = obj.getClass().getField("helpInfo");
            hi = (HelpInfo) helpField.get(null);
        } catch (SecurityException e) {
    		out.println("Not enough security privileges to access help information.");
        } catch (NoSuchFieldException e) {
            // we are expecting this in some cases
        } catch (IllegalArgumentException e) {
    		out.println("Restricted class level security privileges to access help information.");
        } catch (IllegalAccessException e) {
            // this should not happen
            e.printStackTrace();
        }
        if (hi == null) {
    		out.println("No help information, use intMethods to get raw methods information.");
    		return;
        }
        
        Iterator hiIt = hi.methods.entrySet().iterator();
        while (hiIt.hasNext()) {
            Map.Entry iME = (Entry) hiIt.next();
            out.println(iME.getKey() + ": " + iME.getValue());
        }

    }
    
    // support for all methods (internal methods)
    public void intMethods( Object obj) {
        intMethods(obj, 0);
    }

    public void intMethods( Class clazz ) {
    	Method[] m = clazz.getDeclaredMethods();
    	out.println("Class:" + clazz.getName());
    	for (int i=0; i<m.length; i++) { 
    		out.print(m[i].getName());
    		out.print("(");
    		Class[] params = m[i].getParameterTypes();
    		for (int j=0; j<params.length; j++) {
    		    if (j>0) {
        		    out.print(",");
    		    }
    		    out.print(getShortType(params[j]));
    		}
    		out.print("): ");
    		out.print(getShortType(m[i].getReturnType()));
    		out.println("");
    	}
    }

    public void intMethods( Object obj, Integer sup ) {
        intMethods(obj, sup.intValue());
    }

    public void intMethods( Object obj, int sup ) {
        Class clazz = obj.getClass();
        while (sup>0) {
            clazz = clazz.getSuperclass();
            sup--;
        }
        intMethods(clazz);
    }
}